﻿#include "histogramwidget.h"

HistogramWidget::HistogramWidget(const QVector<QVector<double>>& mcolumnData, const QStringList& mcolumnNames, QWidget* parent)
	: columnData(mcolumnData), columnNames(mcolumnNames), QWidget(parent)
{
    initUI();
    // 初始化列名下拉框
    for (int i = 0; i < columnNames.size(); ++i) {
        cmbColumn->addItem(columnNames[i]);
    }
    // 设置默认参数
    spbLineNum->setValue(100);
    int rowNum = columnData[0].size();
    spbLineNum->setMaximum(rowNum);
    if (rowNum < 100) {
        spbLineNum->setValue(rowNum);
    }
    
    spbDecimalNum->setValue(2);
    // 选择第一个列
    cmbColumn->setCurrentIndex(2);
    // 绘制初始直方图
    updateChart();
}

HistogramWidget::~HistogramWidget()
{}

void HistogramWidget::onColumnSelected(int index) {
    updateChart();
}

void HistogramWidget::onDecimalNumChanged(int decimalNum)
{
    updateChart();
}

void HistogramWidget::onLineNumChanged(int lineNum)
{
    updateChart();
}

void HistogramWidget::onFontSizeChanged(int fontsize)
{
    updateChart();
}
void HistogramWidget::onBinNumChanged(int binNum)
{
    updateChart();
}

void HistogramWidget::onNormalizeChecked(int state)
{
    updateChart();
}


void HistogramWidget::initUI()
{
    auto mlayout = new QVBoxLayout(this);
    mlayout->setContentsMargins(0, 0, 0, 0);
    mlayout->setSpacing(0);
    this->setLayout(mlayout);

    QHBoxLayout* hlayout1 = new QHBoxLayout();
    mlayout->addLayout(hlayout1);
    QLabel* label1 = new QLabel("Column:", this);
    label1->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
    hlayout1->addWidget(label1);
    cmbColumn = new QComboBox(this);
    cmbColumn->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
    hlayout1->addWidget(cmbColumn);
    QLabel* label2 = new QLabel("LineNum:", this);
    label2->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
    hlayout1->addWidget(label2);
    spbLineNum = new QSpinBox(this);
    spbLineNum->setRange(1, 9000000);
    spbLineNum->setValue(100);
    spbLineNum->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
    hlayout1->addWidget(spbLineNum);
    QLabel* label3 = new QLabel("BinNum:", this);
    label3->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
    hlayout1->addWidget(label3);
    spbBinNum = new QSpinBox(this);
    spbBinNum->setRange(1, 100);
    spbBinNum->setValue(10);
    spbBinNum->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
    hlayout1->addWidget(spbBinNum);
    QLabel* label = new QLabel("DecimalNum:", this);
    label->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
    hlayout1->addWidget(label);
    spbDecimalNum = new QSpinBox(this);
    spbDecimalNum->setRange(0, 10);
    spbDecimalNum->setValue(2);
    hlayout1->addWidget(spbDecimalNum);
    QLabel* label4 = new QLabel("FontSize:", this);
    label4->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
    hlayout1->addWidget(label4);
    spbFontSize = new QSpinBox(this);
    spbFontSize->setRange(1, 100);
    spbFontSize->setValue(12);
    spbFontSize->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
    hlayout1->addWidget(spbFontSize);
    chkNormalize = new QCheckBox("Normalize", this);
    chkNormalize->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
    hlayout1->addWidget(chkNormalize);
    auto sapcer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
    hlayout1->addItem(sapcer);


    chart = new QChart();
    chart->setTheme(QChart::ChartThemeLight);
    CustomChartView* chartView = new CustomChartView(chart, this);
    chartView->setRenderHint(QPainter::Antialiasing);
    mlayout->addWidget(chartView);

    connect(cmbColumn, SIGNAL(currentIndexChanged(int)), this, SLOT(onColumnSelected(int)));
    connect(spbDecimalNum, SIGNAL(valueChanged(int)), this, SLOT(onDecimalNumChanged(int)));
    connect(spbLineNum, SIGNAL(valueChanged(int)), this, SLOT(onLineNumChanged(int)));
    connect(spbFontSize, SIGNAL(valueChanged(int)), this, SLOT(onFontSizeChanged(int)));
    connect(spbBinNum, SIGNAL(valueChanged(int)), this, SLOT(onFontSizeChanged(int)));
    connect(chkNormalize, SIGNAL(stateChanged(int)), this, SLOT(onNormalizeChecked(int)));
}

void HistogramWidget::calculateStatistics(int columnIndex, double& vmin, double& vmax, double& vmean, double& vvar) {
    const QVector<double>& alldata = columnData[columnIndex];
    int n = std::min(alldata.size(), spbLineNum->value());
    // 使用 mid 方法
    QVector<double> data = alldata.mid(0, n);
    if (chkNormalize->isChecked()) {
        // 归一化处理
        double minVal = *std::min_element(data.begin(), data.end());
        double maxVal = *std::max_element(data.begin(), data.end());
        for (int i = 0; i < data.size(); ++i) {
            data[i] = (data[i] - minVal) / (maxVal - minVal);
        }
    }
    double sum = std::accumulate(data.begin(), data.end(), 0.0);
    double mean = sum / data.size();
    double sq_sum = std::inner_product(data.begin(), data.end(), data.begin(), 0.0);
    double variance = (sq_sum - sum * sum / data.size()) / (data.size() - 1);
    double maxVal = *std::max_element(data.begin(), data.end());
    double minVal = *std::min_element(data.begin(), data.end());

    vmin = minVal;
    vmax = maxVal;
    vmean = mean;
    vvar = variance;
    qDebug() << "Column" << columnNames[columnIndex] << "Mean:" << mean << "Variance:" << variance << "Max:" << maxVal << "Min:" << minVal;
}

void HistogramWidget::updateChart()
{
    // 重新绘制直方图
    int index = cmbColumn->currentIndex();
    if (index >= 0 && index < columnData.size()) {
        // 计算统计数据
        double vmin, vmax, vmean, vvar;
        calculateStatistics(index, vmin, vmax, vmean, vvar);
        // 重新绘制直方图
        QString title = "min:" + QString::number(vmin) + " max:" + QString::number(vmax) + " mean:" + QString::number(vmean) + " variance:" + QString::number(vvar);
        drawHistogram(index, title);
    }
}

void HistogramWidget::drawHistogram(int columnIndex, const QString& title) {
    QBarSeries* series = new QBarSeries();
    series->setName(title);
    

    const QVector<double>& alldata = columnData[columnIndex];
    int n = std::min(alldata.size(), spbLineNum->value());
    // 使用 mid 方法
    QVector<double> data = alldata.mid(0, n);
    std::sort(data.begin(), data.end());
    if (chkNormalize->isChecked()) {
        // 归一化处理
        double minVal = *std::min_element(data.begin(), data.end());
        double maxVal = *std::max_element(data.begin(), data.end());
        for (int i = 0; i < data.size(); ++i) {
            data[i] = (data[i] - minVal) / (maxVal - minVal);
        }
    }

    // 计算直方图的柱子数量
    int binCount = std::min(spbBinNum->value(), static_cast<int>(data.size())); // 设置直方图的柱子数量
    double range = (*(data.end() - 1)) - (*data.begin());
    double binWidth = range / binCount;

    // 填充直方图数据
    QVector<int> counts(binCount, 0);
    QBarSet* barSet = new QBarSet(title);
    for (int i = 0; i < binCount; ++i) {
        double binMinValue = *data.begin() + i * binWidth;
        double binMaxValue = binMinValue + binWidth;
        int count = 0;
        for (double val : data) {
            if (val >= binMinValue && val < binMaxValue) {
                ++count;
            }
        }
        barSet->insert(i, count); // 设置柱子的高度
        counts[i] = count;
    }

    series->append(barSet); // 添加到系列中
    chart->removeAllSeries(); // 清除之前的系列
    chart->addSeries(series);
    chart->createDefaultAxes();

    QFont font;
    font.setPointSize(spbFontSize->value()); // 设置字体大小

    // 获取坐标轴
    QBarCategoryAxis* axisX = new QBarCategoryAxis();
    axisX->setTitleText(columnNames[columnIndex]);
    axisX->setTitleFont(font);
    axisX->setLabelsFont(font);
    for (int i = 0; i < binCount; ++i) {
        double binMinValue = *data.begin() + i * binWidth;
        double value = binMinValue + binWidth / 2;
        QString formattedValue = QString::number(value, 'f', spbDecimalNum->value()); // 保留几位小数
        axisX->append(formattedValue);
    }
    chart->setAxisX(axisX, series);

    // 设置纵坐标轴
    QValueAxis* axisY = new QValueAxis();
    axisY->setRange(0, *(std::max_element(counts.begin(), counts.end())));
    axisY->setTitleText("Frequency");
    axisY->setTitleFont(font);
    axisY->setLabelsFont(font);
    //axisY->setTickCount(5);
    axisY->setLabelFormat("%i");
    chart->setAxisY(axisY, series);
    

    // 设置图例
    chart->legend()->setAlignment(Qt::AlignTop);
    /*chart->legend()->setBackgroundVisible(true);
    chart->legend()->setBrush(QBrush(QColor(128, 128, 128, 128)));
    chart->legend()->setPen(QPen(QColor(192, 192, 192, 192)));*/
    chart->legend()->setFont(font);

    // 设置标题
    chart->setTitle("Histogram of " + columnNames[columnIndex]);
    chart->setFont(font);
}
